<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket JWT Authentication</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }
        h1, h2 {
            color: #333;
        }
        form, .controls, .output {
            margin-bottom: 20px;
        }
        input, button {
            margin-right: 10px;
            padding: 10px;
            font-size: 16px;
        }
        .token-display {
            background-color: #f9f9f9;
            padding: 10px;
            border: 1px solid #ccc;
            margin-top: 10px;
        }
        .output p {
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>WebSocket JWT Authentication</h1>
        <form @submit.prevent="fetchToken">
            <label for="usernameInput">Username:</label>
            <input type="text" v-model="username" placeholder="Enter username">
            <label for="passwordInput">Password:</label>
            <input type="password" v-model="password" placeholder="Enter password">
            <button type="submit">Get Token</button>
            <button type="button" @click="setErrToken">Set Err Token</button>
        </form>

        <div v-if="jwtToken">
            <h2>JWT Token Details</h2>
            <div class="token-display">
                <strong>Raw Token:</strong>
                <p>{{ jwtToken }}</p>
                <strong>Decoded Token:</strong>
                <pre>{{ decodedToken }}</pre>
            </div>
        </div>

        <h2>Test WebSocket Tools</h2>
        <div class="controls">
            <button @click="connectWebSocket" :disabled="!jwtToken || socketConnected">Connect</button>
            <button @click="disconnectWebSocket" :disabled="!socketConnected">Disconnect</button>
            <input type="text" v-model="message" placeholder="Type a message">
            <button @click="sendMessage" :disabled="!socketConnected">Send</button>
            <button @click="sendBinaryMessage" :disabled="!socketConnected">Send Binary</button>
            <button @click="testFunction1" :disabled="!socketConnected">Test Function1</button>
            <button @click="testFunction2" :disabled="!socketConnected">Test Function2</button>
        </div>
        <div class="output">
            <h3>WebSocket Messages</h3>
            <div v-for="msg in messages" :key="msg">{{ msg }}</div>
        </div>
    </div>

    <script>
        new Vue({
            el: "#app",
            data: {
                username: "",
                password: "",
                jwtToken: "",
                decodedToken: null,
                socket: null,
                socketConnected: false,
                message: "",
                messages: [],
                host:location.host,
            },
            methods: {
                async fetchToken() {
                    if (!this.username || !this.password) {
                        alert("Please enter valid credentials.");
                        return;
                    }

                    try {
                        const response = await fetch(`http://${this.host}/token/${this.username}`, {
                            method: "POST",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({ password: this.password }),
                        });

                        if (!response.ok) {
                            throw new Error(`HTTP error! status: ${response.status}`);
                        }

                        const data = await response.json();
                        this.jwtToken = data.access_token;
                        this.decodedToken = this.decodeJWT(this.jwtToken);
                        console.log("Token fetched and set:", this.jwtToken);
                    } catch (error) {
                        console.error("Failed to fetch token:", error);
                        alert("Failed to fetch token. Please check your credentials or server status.");
                    }
                },
                setErrToken() {
                    // Set an invalid token for testing purposes
                    this.jwtToken = "invalid.token.here";
                    this.decodedToken = null;
                },
                decodeJWT(token) {
                    const base64Url = token.split(".")[1];
                    const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
                    return JSON.parse(decodeURIComponent(atob(base64).split("").map((c) => {
                        return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
                    }).join("")));
                },
                connectWebSocket() {
                    if (!this.jwtToken) {
                        alert("Set the access token first!");
                        return;
                    }

                    const wsUrl = `ws://${this.host}/ws/${this.decodedToken.sub}?token=${this.jwtToken}`;
                    this.socket = new WebSocket(wsUrl);

                    this.socket.onopen = () => {
                        console.log("WebSocket connection opened.");
                        this.socketConnected = true;
                    };

                    this.socket.onmessage = (event) => {
                        this.messages.push(event.data);
                    };

                    this.socket.onerror = (error) => {
                        console.error("WebSocket error:", error);
                    };

                    this.socket.onclose = () => {
                        console.log("WebSocket connection closed.");
                        this.socketConnected = false;
                    };
                },
                disconnectWebSocket() {
                    if (this.socket) {
                        this.socket.close();
                    }
                },
                sendMessage() {
                    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
                        this.socket.send(JSON.stringify({ type: "message", content: this.message }));
                        this.message = "";
                    } else {
                        alert("WebSocket is not connected.");
                    }
                },
                sendBinaryMessage() {
                    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
                        // Example binary data (you can replace this with actual binary data)
                        const binaryData = new Uint8Array([1, 2, 3, 4, 5]);
                        this.socket.send(binaryData);
                    } else {
                        alert("WebSocket is not connected.");
                    }
                },
                testFunction1() {
                    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
                        this.socket.send(JSON.stringify({ router: "function1", data: { message: "Test message for function1" } }));
                    } else {
                        alert("WebSocket is not connected.");
                    }
                },
                testFunction2() {
                    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
                        this.socket.send(JSON.stringify({ router: "function2", data: { number: 5 } }));
                    } else {
                        alert("WebSocket is not connected.");
                    }
                },
            },
        });
    </script>
</body>
</html>